"""
基础数据模块API视图
"""
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from django.db.models import Q, Avg
from django.db.models import Count
from .models import College, Major, Classes, Course, Punish, Score, PunishDict
from .serializers import (
    CollegeSerializer, MajorSerializer, ClassesSerializer,
    CourseSerializer, PunishSerializer, ScoreSerializer, PunishDictSerializer
)
from grade_detail.models import GradeDetail


class CollegeViewSet(viewsets.ModelViewSet):
    """
    学院管理ViewSet
    提供学院的CRUD操作
    """
    queryset = College.objects.all()
    serializer_class = CollegeSerializer
    permission_classes = [IsAuthenticated]
    
    def create(self, request, *args, **kwargs):
        """创建学院（仅管理员）"""
        if not request.user.is_staff:
            return Response({'code': 403, 'message': '权限不足'}, status=status.HTTP_403_FORBIDDEN)
        return super().create(request, *args, **kwargs)


class MajorViewSet(viewsets.ModelViewSet):
    """
    专业管理ViewSet
    提供专业的CRUD操作，支持按学院筛选
    """
    queryset = Major.objects.all().select_related('college')
    serializer_class = MajorSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        queryset = Major.objects.all().select_related('college')
        college_id = self.request.query_params.get('college', None)
        if college_id:
            queryset = queryset.filter(college_id=college_id)
        return queryset


class ClassesViewSet(viewsets.ModelViewSet):
    """
    班级管理ViewSet
    提供班级的CRUD操作，支持按专业筛选
    """
    queryset = Classes.objects.all().select_related('teacher', 'major')
    serializer_class = ClassesSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        queryset = Classes.objects.all().select_related('teacher', 'major')
        major_id = self.request.query_params.get('major', None)
        if major_id:
            queryset = queryset.filter(major_id=major_id)
        return queryset


class CourseViewSet(viewsets.ModelViewSet):
    """
    课程管理ViewSet
    提供课程的CRUD操作
    """
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
    permission_classes = [IsAuthenticated]
    
    @action(detail=False, methods=['post'])
    def sync_from_grades(self, request):
        """
        从成绩数据中同步课程
        自动提取所有成绩记录中的课程，生成课程字典
        """
        if not request.user.is_staff:
            return Response({'code': 403, 'message': '权限不足'}, status=status.HTTP_403_FORBIDDEN)
        
        try:
            # 查找所有不重复的课程
            grade_courses = GradeDetail.objects.values('course_no', 'course_name').distinct()
            
            created_count = 0
            updated_count = 0
            skipped_count = 0
            
            for item in grade_courses:
                course_no = item['course_no']
                course_name = item['course_name']
                
                # 跳过无效数据
                if not course_no or not course_name:
                    skipped_count += 1
                    continue
                
                # 查找或创建课程
                course, created = Course.objects.get_or_create(
                    course_name=course_name,
                    defaults={'course_name': course_name}
                )
                
                if created:
                    created_count += 1
                else:
                    updated_count += 1
            
            return Response({
                'code': 200,
                'message': '同步成功',
                'data': {
                    'created': created_count,
                    'updated': updated_count,
                    'skipped': skipped_count,
                    'total': created_count + updated_count + skipped_count
                }
            })
        
        except Exception as e:
            return Response({
                'code': 500,
                'message': f'同步失败：{str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class PunishViewSet(viewsets.ModelViewSet):
    """
    处分管理ViewSet
    提供处分的CRUD操作，支持按学生、年份筛选
    """
    queryset = Punish.objects.all().select_related('teacher', 'student')
    serializer_class = PunishSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        queryset = Punish.objects.all().select_related('teacher', 'student')
        
        # 学生筛选
        student_id = self.request.query_params.get('student', None)
        if student_id:
            queryset = queryset.filter(student_id=student_id)
        
        # 年份筛选
        time = self.request.query_params.get('time', None)
        if time:
            queryset = queryset.filter(time=time)
        
        return queryset
    
    def create(self, request, *args, **kwargs):
        """创建处分（仅教师及以上）"""
        if not request.user.is_staff:
            return Response({'code': 403, 'message': '权限不足'}, status=status.HTTP_403_FORBIDDEN)
        return super().create(request, *args, **kwargs)


class PunishDictViewSet(viewsets.ModelViewSet):
    """
    处分字典管理ViewSet
    提供处分字典的CRUD操作
    """
    queryset = PunishDict.objects.all()
    serializer_class = PunishDictSerializer
    permission_classes = [IsAuthenticated]
    
    def create(self, request, *args, **kwargs):
        """创建处分字典（仅管理员）"""
        if not request.user.is_staff:
            return Response({'code': 403, 'message': '权限不足'}, status=status.HTTP_403_FORBIDDEN)
        return super().create(request, *args, **kwargs)


class ScoreViewSet(viewsets.ModelViewSet):
    """
    综测分管理ViewSet
    
    提供综测分的操作:
        - list: 获取综测分列表
        - retrieve: 获取综测分详情
        - calculate: 计算综测分
        - ranking: 综测分排名
    """
    queryset = Score.objects.all().select_related('student', 'student__profile')
    serializer_class = ScoreSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        """根据用户权限返回不同的查询集"""
        user = self.request.user
        queryset = Score.objects.all().select_related('student', 'student__profile')
        
        # 学生只能看到自己的综测分
        if not user.is_staff:
            queryset = queryset.filter(student=user)
        
        # 学生筛选（支持按学号、姓名或ID查询）
        student_param = self.request.query_params.get('student', None)
        if student_param:
            # 尝试按学号、姓名或ID查询
            queryset = queryset.filter(
                Q(student__profile__student_id__icontains=student_param) | 
                Q(student__username__icontains=student_param) |
                Q(student__first_name__icontains=student_param) |
                Q(student_id=student_param) if student_param.isdigit() else Q()
            )
        
        # 年份筛选
        time = self.request.query_params.get('time', None)
        if time:
            queryset = queryset.filter(time=time)
        
        # 班级筛选
        class_name = self.request.query_params.get('class_name', None)
        if class_name:
            queryset = queryset.filter(student__profile__class_name__icontains=class_name)
        
        return queryset
    
    @action(detail=False, methods=['post'])
    def calculate(self, request):
        """
        计算综测分
        
        接口：POST /api/scores/calculate/
        权限：仅教师及以上
        
        参数:
            - student: 学生ID（可选，不传则计算所有学生）
            - time: 学年（必填）
            - grade_level: 年级（必填：大一/大二/大三/大四）
        
        计算规则：
            1. 基本智育分 = 该学年所有课程平均分（排除体育课）× 70%
            2. 基本德育分 = 80分 × 20%
            3. 基本体育分：
               - 大一、大二：体育课平均分 × 10%
               - 大三、大四：直接给10分（满分）
            4. 附加分 = 附加智育分 + 附加德育分 + 附加体育分（默认0）
            5. 扣分 = 处分扣分总和
            6. 综测总分 = 智育分 + 德育分 + 体育分 + 附加分 - 扣分
        
        返回：计算结果统计
        """
        if not request.user.is_staff:
            return Response({'code': 403, 'message': '权限不足'}, status=status.HTTP_403_FORBIDDEN)
        
        student_id = request.data.get('student', None)
        time = request.data.get('time', None)
        grade_level = request.data.get('grade_level', None)
        
        if not time:
            return Response({
                'code': 400,
                'message': '请指定学年'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        if not grade_level:
            return Response({
                'code': 400,
                'message': '请指定年级（大一/大二/大三/大四）'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        if grade_level not in ['大一', '大二', '大三', '大四']:
            return Response({
                'code': 400,
                'message': '年级参数错误，必须是：大一、大二、大三或大四'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            # 确定要计算的学生
            if student_id:
                from django.contrib.auth.models import User
                students = User.objects.filter(id=student_id)
            else:
                # 查找该学年有成绩的所有学生
                student_ids = GradeDetail.objects.filter(time=time).values_list('student_id', flat=True).distinct()
                from django.contrib.auth.models import User
                students = User.objects.filter(id__in=student_ids)
            
            success_count = 0
            fail_count = 0
            errors = []
            
            for student in students:
                try:
                    # 1. 计算基本智育分（该学年所有课程平均分，排除体育课）× 70%
                    grades = GradeDetail.objects.filter(student=student, time=time)
                    grade_numbers = []
                    fail_count_courses = 0
                    
                    for grade in grades:
                        # 排除体育课
                        if '体育' in grade.course_name:
                            continue
                        try:
                            grade_num = float(grade.grade)
                            grade_numbers.append(grade_num)
                            if grade_num < 60:
                                fail_count_courses += 1
                        except:
                            pass
                    
                    if not grade_numbers:
                        errors.append(f'学生{student.username}在{time}学年没有有效成绩数据（排除体育课后），跳过')
                        fail_count += 1
                        continue
                    
                    zb_avg = sum(grade_numbers) / len(grade_numbers)
                    zb_grade = zb_avg * 0.7  # 乘以70%
                    
                    # 2. 基本德育分（固定80分）
                    db_grade = 80.0
                    
                    # 3. 基本体育分（根据年级判断）
                    # 大一、大二：体育课平均分 × 10%
                    # 大三、大四：直接给10分（满分）
                    if grade_level in ['大三', '大四']:
                        tb_grade = 10.0  # 大三大四直接给满分10分
                    else:
                        # 大一大二：计算体育课平均分 × 10%
                        tb_grade = 0.0
                        tb_courses = grades.filter(course_name__icontains='体育')
                        if tb_courses.exists():
                            tb_numbers = []
                            for tb_course in tb_courses:
                                try:
                                    tb_num = float(tb_course.grade)
                                    tb_numbers.append(tb_num)
                                except:
                                    pass
                            if tb_numbers:
                                # 计算平均分后乘以10%，存储的是加权后的分数
                                tb_avg = sum(tb_numbers) / len(tb_numbers)
                                tb_grade = tb_avg * 0.1
                    
                    # 4. 附加分（默认为0，可后续手动修改）
                    za_grade = 0.0
                    da_grade = 0.0
                    ta_grade = 0.0
                    
                    # 5. 处分扣分
                    punishments = Punish.objects.filter(student=student, time=time)
                    total_deduction = sum([p.grade for p in punishments if p.grade])
                    
                    # 6. 计算综测总分
                    # 综测分 = 智育分(已是×70%) + 德育分×20% + 体育分(已是×10%) + 附加分 - 扣分
                    # 注意：zb_grade和tb_grade都已经是加权后的值
                    basic_score = zb_grade + db_grade * 0.2 + tb_grade
                    additional_score = za_grade + da_grade + ta_grade
                    final_score = basic_score + additional_score - total_deduction
                    
                    # 7. 保存或更新综测分记录
                    score, created = Score.objects.update_or_create(
                        student=student,
                        time=time,
                        defaults={
                            'grade_level': grade_level,
                            'grade': round(final_score, 3),
                            'zb_grade': round(zb_grade, 3),
                            'db_grade': round(db_grade, 3),
                            'tb_grade': round(tb_grade, 3),
                            'za_grade': round(za_grade, 3),
                            'da_grade': round(da_grade, 3),
                            'ta_grade': round(ta_grade, 3),
                            'fail': fail_count_courses
                        }
                    )
                    
                    success_count += 1
                    
                except Exception as e:
                    errors.append(f'学生{student.username}计算失败：{str(e)}')
                    fail_count += 1
            
            return Response({
                'code': 200,
                'message': '计算完成',
                'data': {
                    'success_count': success_count,
                    'fail_count': fail_count,
                    'total': success_count + fail_count,
                    'errors': errors[:50]  # 最多返回50条错误信息
                }
            })
        
        except Exception as e:
            return Response({
                'code': 500,
                'message': f'计算失败：{str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    @action(detail=True, methods=['get'])
    def formula(self, request, pk=None):
        """
        获取综测分计算公式详情
        
        接口：GET /api/scores/{id}/formula/
        权限：已认证用户
        
        返回该综测分的详细计算过程，包括：
        - 基本智育分计算（该学年所有课程平均分）
        - 基本德育分计算（固定分值或计算规则）
        - 基本体育分计算（体育课成绩）
        - 附加智育分、德育分、体育分
        - 处分扣分明细
        - 最终综测分计算公式
        
        返回示例:
        {
            "student_info": {"student_id": "2023001", "student_name": "张三", "class_name": "计231"},
            "time": 2024,
            "basic_scores": {
                "zb_grade": {"value": 85.5, "formula": "(85+86+84+87)/4", "courses": [{...}]},
                "db_grade": {"value": 80, "formula": "基础分80分"},
                "tb_grade": {"value": 90, "formula": "体育课成绩"}
            },
            "additional_scores": {
                "za_grade": {"value": 5, "items": [...]},
                "da_grade": {"value": 3, "items": [...]},
                "ta_grade": {"value": 2, "items": [...]}
            },
            "deductions": [{"type": "处分", "name": "迟到", "score": -2}],
            "final_formula": "(85.5*0.7 + 80*0.2 + 90*0.1) + 5 + 3 + 2 - 2 = 95.85",
            "final_score": 95.85
        }
        """
        try:
            score = self.get_object()
            student = score.student
            time = score.time
            
            # 学生信息
            student_info = {
                'student_id': student.profile.student_id if hasattr(student, 'profile') and student.profile else student.username,
                'student_name': student.first_name or student.username,
                'class_name': student.profile.class_name if hasattr(student, 'profile') and student.profile else '-',
                'major': student.profile.major if hasattr(student, 'profile') and student.profile else '-'
            }
            
            # 1. 基本智育分计算（该学年所有课程平均分，排除体育课）× 70%
            grades = GradeDetail.objects.filter(student=student, time=time)
            course_list = []
            grade_numbers = []
            
            for grade in grades:
                # 排除体育课
                if '体育' in grade.course_name:
                    continue
                try:
                    grade_num = float(grade.grade)
                    grade_numbers.append(grade_num)
                    course_list.append({
                        'course_name': grade.course_name,
                        'grade': grade.grade
                    })
                except:
                    pass
            
            if grade_numbers:
                zb_avg = sum(grade_numbers) / len(grade_numbers)
                zb_value = zb_avg * 0.7  # 乘以70%
                zb_formula = '课程成绩：' + ' + '.join([str(g) for g in grade_numbers]) + f' = {sum(grade_numbers)}\n' \
                            f'平均分: {sum(grade_numbers)} ÷ {len(grade_numbers)} = {zb_avg:.2f}\n' \
                            f'基本智育分：{zb_avg:.2f} × 70% = {zb_value:.2f}'
            else:
                zb_avg = 0
                zb_value = 0
                zb_formula = '无成绩数据'
            
            # 2. 基本德育分（固定80分或从数据库获取）
            db_value = float(score.db_grade) if score.db_grade else 80
            db_formula = f'基础德育分：{db_value}分'
            
            # 3. 基本体育分（该学年所有体育课的平均分 × 10%）
            # 注意：数据库中存储的tb_grade已经是乘以10%后的值
            tb_value = float(score.tb_grade) if score.tb_grade else 0
            tb_courses = grades.filter(course_name__icontains='体育')
            tb_course_list = []
            tb_numbers = []
            
            if tb_courses.exists():
                for tb_course in tb_courses:
                    try:
                        tb_num = float(tb_course.grade)
                        tb_numbers.append(tb_num)
                        tb_course_list.append({
                            'course_name': tb_course.course_name,
                            'grade': tb_course.grade
                        })
                    except:
                        pass
                
                if tb_numbers:
                    tb_avg = sum(tb_numbers) / len(tb_numbers)
                    tb_value = tb_avg * 0.1  # 乘以10%
                    tb_formula = '体育课平均分：(' + ' + '.join([str(g) for g in tb_numbers]) + f') ÷ {len(tb_numbers)} = {tb_avg:.2f}\n' \
                                f'基本体育分：{tb_avg:.2f} × 10% = {tb_value:.2f}'
                else:
                    tb_formula = f'体育分：{tb_value}分（体育课成绩非数字）'
            else:
                tb_formula = f'体育分：{tb_value}分（未找到体育课成绩）'
            
            # 4. 附加分（从数据库获取）
            za_value = float(score.za_grade) if score.za_grade else 0
            da_value = float(score.da_grade) if score.da_grade else 0
            ta_value = float(score.ta_grade) if score.ta_grade else 0
            
            # 5. 处分扣分明细
            punishments = Punish.objects.filter(student=student, time=time)
            deductions = []
            total_deduction = 0
            
            for p in punishments:
                deduction_score = p.grade if p.grade else 0
                deductions.append({
                    'type': '处分',
                    'sort': p.sort,
                    'name': p.name,
                    'ranks': p.ranks,
                    'score': -deduction_score
                })
                total_deduction += deduction_score
            
            # 6. 综测分计算公式（智育分(已是70%) + 德育分20% + 体育分(已是10%) + 附加分 - 扣分）
            # zb_value 和 tb_value 都已经是乘以权重后的值
            db_weighted = db_value * 0.2
            
            basic_total = zb_value + db_weighted + tb_value
            additional_total = za_value + da_value + ta_value
            final_score = basic_total + additional_total - total_deduction
            
            # 获取原始平均分用于显示
            tb_avg_display = (tb_value / 0.1) if tb_value > 0 else 0
            
            final_formula = f"综测分 = 基本智育分 + (基本德育分 × 20%) + 基本体育分 + 附加分 - 扣分\n" \
                          f"= ({zb_avg:.2f} × 0.7) + ({db_value:.2f} × 0.2) + ({tb_avg_display:.2f} × 0.1) + ({za_value:.2f} + {da_value:.2f} + {ta_value:.2f}) - {total_deduction:.2f}\n" \
                          f"= {zb_value:.2f} + {db_weighted:.2f} + {tb_value:.2f} + {additional_total:.2f} - {total_deduction:.2f}\n" \
                          f"= {basic_total:.2f} + {additional_total:.2f} - {total_deduction:.2f}\n" \
                          f"= {final_score:.2f}"
            
            return Response({
                'code': 200,
                'message': '成功',
                'data': {
                    'student_info': student_info,
                    'time': time,
                    'basic_scores': {
                        'zb_grade': {
                            'name': '基本智育分',
                            'value': round(zb_value, 2),
                            'weight': '70%',
                            'weighted_value': round(zb_value, 2),  # 已经是加权后的值
                            'formula': zb_formula,
                            'courses': course_list,
                            'course_count': len(course_list)
                        },
                        'db_grade': {
                            'name': '基本德育分',
                            'value': round(db_value, 2),
                            'weight': '20%',
                            'weighted_value': round(db_weighted, 2),
                            'formula': db_formula
                        },
                        'tb_grade': {
                            'name': '基本体育分',
                            'value': round(tb_value, 2),
                            'weight': '10%',
                            'weighted_value': round(tb_value, 2),  # 已经是加权后的值
                            'formula': tb_formula,
                            'courses': tb_course_list,
                            'course_count': len(tb_course_list)
                        }
                    },
                    'additional_scores': {
                        'za_grade': {
                            'name': '附加智育分',
                            'value': round(za_value, 2)
                        },
                        'da_grade': {
                            'name': '附加德育分',
                            'value': round(da_value, 2)
                        },
                        'ta_grade': {
                            'name': '附加体育分',
                            'value': round(ta_value, 2)
                        }
                    },
                    'deductions': deductions,
                    'total_deduction': round(total_deduction, 2),
                    'summary': {
                        'basic_total': round(basic_total, 2),
                        'additional_total': round(additional_total, 2),
                        'deduction_total': round(total_deduction, 2),
                        'final_score': round(final_score, 2)
                    },
                    'final_formula': final_formula,
                    'final_score': round(final_score, 2),
                    'stored_score': float(score.grade) if score.grade else 0
                }
            })
        
        except Exception as e:
            return Response({
                'code': 500,
                'message': f'获取计算公式失败：{str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    @action(detail=False, methods=['get'])
    def ranking(self, request):
        """
        综测分排名
        
        参数:
            - time: 学年（必填）
            - scope: 范围（class/major/college）
            - scope_value: 范围值
        """
        time = request.query_params.get('time')
        if not time:
            return Response({'code': 400, 'message': '缺少学年参数'}, status=status.HTTP_400_BAD_REQUEST)
        
        scope = request.query_params.get('scope', 'class')
        scope_value = request.query_params.get('scope_value', None)
        
        queryset = Score.objects.filter(time=time).select_related('student', 'student__profile')
        
        # 根据范围筛选
        if scope == 'class' and scope_value:
            queryset = queryset.filter(student__profile__class_name=scope_value)
        elif scope == 'major' and scope_value:
            queryset = queryset.filter(student__profile__major=scope_value)
        
        # 按综测分降序排序
        queryset = queryset.order_by('-grade')
        
        # 添加排名
        results = []
        for rank, score in enumerate(queryset, start=1):
            serializer = self.get_serializer(score)
            data = serializer.data
            data['rank'] = rank
            results.append(data)
        
        return Response({
            'count': len(results),
            'results': results
        })
